公式のテンプレートスニペットでAurora Autoscaingを設定しようと思ったらハマった話
どーもsutoです。
AuroraのリードレプリカのAutoscaling設定をCloudFormationで作成しようとAWS公式ページのAutoscalingテンプレートスニペットをコピペしてスタック作成したところ、エラーとなってスタックが完了しなかった話をします。
ハマったところ
こちら公式ページの「Aurora DB クラスターのスケーリングポリシーの宣言」の内容でAuroraのAutoscaling設定を作成できるか検証してみたところ、
「No scalable target registered for 〜〜」というエラーメッセージが表示され、ロールバックしてしまいました。
多少数値を変えたりDBクラスター識別子を自分の検証用の名前に変えたりはしましたが、公式ページとまったく同じプロパティを使っているのに何故なんだ〜!
当初は「まさか公式で紹介しているコードが間違っているわけないよな」と思い込み、7〜8回再試行してみましたが何故か1回だけCREATE_COMPLETEでき、残りの試行は全てROLLBACKに。
むしろ何故1回だけ成功した?
これって低確率で成功するテンプレなのか。。。(そんなわけがないだろ!)とテンパリつつも、冷静にエラーメッセージを確認。
対策について
scalable targetが見つからないというエラーだから、テンプレート内にある「ScalableTarget」が先にリソース作成されないとダメなのか。ということはリソース作成の優先順位をしっかりつければいいいのだろうけど、プロパティのなかで他に代替できる項目があるかな〜?
てなわけで公式ページのリファレンスを眺めてみると、
あー、この「ScalindTargetId」に置き換えればいいんじゃない?と思い、以下のようにテンプレートを修正しました。
ScalableTarget: Type: AWS::ApplicationAutoScaling::ScalableTarget Properties: MaxCapacity: 3 MinCapacity: 1 RoleARN: Fn::Sub: 'arn:aws:iam::${AWS::AccountId}:role/aws-service-role/rds.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_RDSCluster' ServiceNamespace: rds ScalableDimension: 'rds:cluster:ReadReplicaCount' ResourceId: !Sub cluster:${SampleDBCluster} ScalingPolicyDBCluster: Type: AWS::ApplicationAutoScaling::ScalingPolicy Properties: PolicyName: !Sub ${SampleDBCluster}-asg PolicyType: TargetTrackingScaling ScalingTargetId: !Ref ScalableTarget TargetTrackingScalingPolicyConfiguration: TargetValue: 80 PredefinedMetricSpecification: PredefinedMetricType: RDSReaderAverageCPUUtilization ScaleInCooldown: 600 ScaleOutCooldown: 300
{SampleDBCluster}は既存のAuroraDBクラスター識別子が入ります。
これでスタックを実行してみると、
無事STACK_COMPLETEになりました!(もちろん成功率100%です!!)
リードレプリカがAutoscalingするAuroraDBを作成するテンプレート
せっかくトラブルが解決できたので、Auroraクラスターもまとめて新規作成できるようなテンプレートを作ってみました。
- 構成は、クラスター:1台、Writerノード:1台、Readerノード:1台
- CPU使用率70%以上でReaderノードがスケール
- スケールキャパシティは、最小:1、最大:3
- クールダウンは、スケールイン:10分、スケールアウト:5分
- masterユーザ名/パスワードはSecret Managerで自動生成
- "DeletionProtection"は、本番利用時にはコメント(#)を外して設定するようにしましょう。
AWSTemplateFormatVersion: "2010-09-09" Description: Provision of Aurora MySQL Parameters: ProjectName: Description: ProjectName Type: String EngineVersion: Type: String InstanceClass: Type: String VPCId: Type: String Description: ID for VPC. PrimarySubnetId: Type: String Description: Subnet id on which Aurora instance locates. SecondarySubnetId: Type: String Description: Subnet id on which Aurora instance locates. EC2SGId: Type: String Description: ID for EC2 Security Group. Resources: SampleDBCluster: Type: AWS::RDS::DBCluster Properties: DBClusterIdentifier: !Sub ${ProjectName}-auroradb DBClusterParameterGroupName: !Ref 'SampleDBClusterParameterGroup' DBSubnetGroupName: !Ref SampleDBSubnetGroup Engine: aurora-mysql EngineVersion: !Ref 'EngineVersion' MasterUserPassword: !Sub "{{resolve:secretsmanager:${AuroraDBSecret}:SecretString:password::}}" MasterUsername: !Sub '{{resolve:secretsmanager:${AuroraDBSecret}:SecretString:username}}' VpcSecurityGroupIds: - !GetAtt 'SampleSecurityGroup.GroupId' #DeletionProtection: 'True' PreferredMaintenanceWindow: 'Sun:14:30-Sun:15:00' Tags: - Key: Name Value: !Sub ${ProjectName}-aurora - Key: backup Value: 'True' SampleDBClusterParameterGroup: Type: AWS::RDS::DBClusterParameterGroup Properties: Description: !Sub ${ProjectName}-aurora Family: aurora-mysql5.7 Parameters: time_zone: Asia/Tokyo SampleDBInstanceA: Type: AWS::RDS::DBInstance Properties: DBClusterIdentifier: !Ref 'SampleDBCluster' DBInstanceClass: !Ref 'InstanceClass' Engine: aurora-mysql PreferredMaintenanceWindow: 'Sun:15:00-Sun:15:30' SampleDBInstanceB: Type: AWS::RDS::DBInstance Properties: DBClusterIdentifier: !Ref 'SampleDBCluster' DBInstanceClass: !Ref 'InstanceClass' Engine: aurora-mysql PreferredMaintenanceWindow: 'Sun:15:30-Sun:16:00' SampleDBSubnetGroup: Type: AWS::RDS::DBSubnetGroup Properties: DBSubnetGroupDescription: sample-aurora DBSubnetGroupName: !Sub ${ProjectName}-aurora-nw SubnetIds: - !Ref PrimarySubnetId - !Ref SecondarySubnetId SampleSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: !Sub ${ProjectName}-aurora SecurityGroupIngress: - SourceSecurityGroupId: !Ref EC2SGId FromPort: 3306 IpProtocol: tcp ToPort: 3306 VpcId: !Ref VPCId AuroraDBSecret: Type: AWS::SecretsManager::Secret Properties: GenerateSecretString: SecretStringTemplate: '{"username": "admin"}' GenerateStringKey: "password" PasswordLength: 16 ExcludeCharacters: '"@/\' Name: !Sub ${ProjectName}-aurora-secret ScalableTarget: Type: AWS::ApplicationAutoScaling::ScalableTarget Properties: MaxCapacity: 3 MinCapacity: 1 RoleARN: Fn::Sub: 'arn:aws:iam::${AWS::AccountId}:role/aws-service-role/rds.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_RDSCluster' ServiceNamespace: rds ScalableDimension: 'rds:cluster:ReadReplicaCount' ResourceId: !Sub cluster:${SampleDBCluster} ScalingPolicyDBCluster: Type: AWS::ApplicationAutoScaling::ScalingPolicy Properties: PolicyName: !Sub ${SampleDBCluster}-asg PolicyType: TargetTrackingScaling ScalingTargetId: !Ref ScalableTarget TargetTrackingScalingPolicyConfiguration: TargetValue: 80 PredefinedMetricSpecification: PredefinedMetricType: RDSReaderAverageCPUUtilization ScaleInCooldown: 600 ScaleOutCooldown: 300 Outputs: GetSecretValueByCLI: Value: !Sub |+ aws secretsmanager get-secret-value --secret-id ${AuroraDBSecret} --region ${AWS::Region} --query SecretString
まとめ
冒頭で紹介したように、公式ページのスニペットをそのまま使おうとすると私と同じエラーを経験をすることになるかと思うのでご注意を。
同じ境遇になった方や、これから似たようなテンプレを作ろうとしている方に本記事が参考になれば幸いです。